/**
 * 广寒宫
 * 网址:www.guanghangong.xyz
 */
package org.moon.framework.autoconfigure.oss.impl;

import io.minio.MinioClient;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import org.moon.framework.autoconfigure.MoonConstants;
import org.moon.framework.autoconfigure.exception.domain.MoonException;
import org.moon.framework.autoconfigure.oss.OssService;
import org.moon.framework.autoconfigure.oss.domain.MoonFile;
import org.moon.framework.autoconfigure.oss.props.OssProperties;
import org.moon.framework.autoconfigure.oss.utils.OssUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * minio 服务
 * @author moon
 */
@Slf4j
public class MinioOssProviderImpl implements OssService,OssProvider {

    private static final long DEFAULT_CONNECTION_TIMEOUT = 15 * 60;

    private MinioClient client;
    private OssProperties ossProperties;

    @Override
    @SneakyThrows
    public OssService builder(OssProperties ossProperties) {
        List<Protocol> protocol = new LinkedList<>();
        protocol.add(Protocol.HTTP_1_1);
        OkHttpClient httpClient = new OkHttpClient();
        boolean secure = !(ossProperties.getEndpoint() != null && ossProperties.getEndpoint().startsWith("http://"));
        if (secure) {
            httpClient = httpClient.newBuilder()
                    .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .protocols(protocol)
                    .hostnameVerifier((s, sslSession) -> true)
                    .connectionSpecs(Collections.singletonList(ConnectionSpec.COMPATIBLE_TLS))
                    .build();
        } else {
            httpClient = httpClient.newBuilder()
                    .connectTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
                    .protocols(protocol)
                    .hostnameVerifier((s, sslSession) -> true)
                    .connectionSpecs(Collections.singletonList(ConnectionSpec.CLEARTEXT))
                    .build();
        }
        client = new MinioClient(ossProperties.getEndpoint(), 0, ossProperties.getAccessKey(), ossProperties.getSecretKey(), null, secure, httpClient);
        this.ossProperties = ossProperties;
        return this;
    }

    @Override
    public MoonFile putFile(MultipartFile file) {
        return putFile(file.getOriginalFilename(),file);
    }

    @Override
    public MoonFile putFile(String fileName, MultipartFile file) {
        try {
            String bucketName = OssUtils.getBucketName(ossProperties.getBucketName());
            if (!this.client.bucketExists(bucketName)) {
                this.client.makeBucket(bucketName);
//                this.client.setBucketPolicy(bucketName, getPolicyType(this.getBucketName(bucketName), PolicyType.READ));
            }
            String originalName = fileName;
            fileName = OssUtils.getFileName(fileName);
            InputStream stream = file.getInputStream();
            this.client.putObject(bucketName, fileName, stream, (long)stream.available(), null, null, "application/octet-stream");
            MoonFile moonFile = MoonFile.builder().originalName(originalName).name(fileName).domain(this.ossProperties.getEndpoint()).link(bucketName.concat("/").concat(fileName)).build();
            return moonFile;
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.FAIL.getCode(),"上传文件失败",e);
        }
    }

    @Override
    public void removeFiles(List<String> fileNames) {
        try {
            this.client.removeObjects(OssUtils.getBucketName(ossProperties.getBucketName()), fileNames);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.FAIL.getCode(),"删除文件失败",e);
        }
    }

    @Override
    public void removeFile(String fileName) {
        try {
            this.client.removeObject(OssUtils.getBucketName(ossProperties.getBucketName()), fileName);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.FAIL.getCode(),"删除文件失败",e);
        }
    }
}
